#!/sbin/openrc-run
#
# Control Groups Configuration Startup
#
# This script runs the cgconfigparser utility to parse and setup
# the control group filesystem. It uses ${CONFIG_FILE}
# and parses the configuration specified in there.
#
CGCONFIGPARSER="/usr/sbin/cgconfigparser"
CGROUP_FS="cgroup"
CONFIG_FILE=${CONFIG_FILE:-"/etc/cgroup/cgconfig.conf"}
MOUNTS_FILE="/proc/mounts"
RULES_FILE="/etc/cgroup/cgrules.conf"

# Support multiple mount points
MAX_INDEX=0
declare -a MOUNT_POINTS MOUNT_OPTIONS

move_all_to_init_class() {
	local i
	for i in $(seq 1 ${MAX_INDEX}); do
		cd ${MOUNT_POINTS[$i]}

		if grep -qw ${MOUNT_POINTS[$i]} ${MOUNTS_FILE}; then
			local directory
			for directory in $(find . -depth -type d); do
				if [[ ${directory} != "." ]]; then
					# cat fails with "Argument list too long" error
					sed -nu p < ${directory}/tasks > tasks
					rmdir ${directory}
				fi
			done
		else
			ewarn "Resource control filesystem not mounted"
		fi

		cd - >/dev/null
	done
}

parse_mounts() {
	local device mount_point fs_type options other
	while read device mount_point fs_type options other; do
		if grep -q ${device} <<< ${CGROUP_FS}; then
			let MAX_INDEX++
			MOUNT_POINTS[${MAX_INDEX}]=${mount_point}
			MOUNT_OPTIONS[${MAX_INDEX}]=${options}
		fi
	done < ${MOUNTS_FILE}
}

umount_fs() {
	local i
	for i in $(seq 1 ${MAX_INDEX}); do
		umount ${MOUNT_POINTS[$i]}
		rmdir ${MOUNT_POINTS[$i]}
	done
}

start() {
	ebegin "Starting cgconfig service"

	# Mount filesystem and create cgroups
	if ! ${CGCONFIGPARSER} -l ${CONFIG_FILE} >/dev/null; then
		eend 1 "Failed to parse ${CONFIG_FILE}"
		return 1
	fi

	parse_mounts

	# Find default cgroup name in rules file
	local default_cgroup
	if [[ -f ${RULES_FILE} ]]; then
		local user controller
		read user controller default_cgroup <<< $(grep -m1 '^\*\s' ${RULES_FILE})
		if [[ $default_cgroup == "*" ]]; then
			ewarn "${RULES_FILE} incorrect"
			ewarn "Overriding it"
			default_cgroup=
		fi
	fi
	# Use predefined name if none was found
	if [[ -z ${default_cgroup} ]]; then
		default_cgroup=sysdefault
	fi

	# Create a default cgroup for tasks to return back to
	local i
	for i in $(seq 1 ${MAX_INDEX}); do
		# Ignore if directory already exists
		mkdir -p ${MOUNT_POINTS[$i]}/${default_cgroup}
		find ${MOUNT_POINTS[$i]}/ -name tasks | xargs  chmod a+rw
		chmod go-w ${MOUNT_POINTS[$i]}/tasks

		# Special rule for cpusets
		if grep -qw cpuset <<< ${MOUNT_OPTIONS[$i]}; then
			cat ${MOUNT_POINTS[$i]}/cpuset.cpus > ${MOUNT_POINTS[$i]}/${default_cgroup}/cpuset.cpus
			cat ${MOUNT_POINTS[$i]}/cpuset.mems > ${MOUNT_POINTS[$i]}/${default_cgroup}/cpuset.mems
		fi

		# Classify everything to default cgroup
		local j
		for j in $(ps --no-headers -eL o tid); do
			echo $j > ${MOUNT_POINTS[$i]}/${default_cgroup}/tasks 2>/dev/null
		done
	done

	eend 0
}

stop() {
	ebegin "Stopping cgconfig service"
	parse_mounts
	move_all_to_init_class
	umount_fs
	eend 0
}
